package spring.DI;

import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import spring.DI.ltw.IndexServiceMyself;
import spring.DI.methodDI.BeansConfig;
import spring.factoryBean.ColorEnum;

import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
 * 依赖注入测试类： @Autowired 和 @Resource 选取 Bean的顺序。
 *
 * 使用 @EnableSpringConfigured + @Configurable 时，需要增加如下 JVM配置
 *      -javaagent:E:/Repos/maven/org/springframework/spring-instrument/5.1.7.RELEASE/spring-instrument-5.1.7.RELEASE.jar
 *
 */
public class TestSpringDI {
    private static final Logger logger = LoggerFactory.getLogger(TestSpringDI.class);

    public static void main(String[] args) {

        // 普通方式
        // AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

        // 多环境调用方式
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // qqq 环境下不存在叫 indexDaoImpl3 的 Bean, 所以会报错: 没有唯一的 Bean
        context.getEnvironment().setActiveProfiles("qqq");
        context.register(DIConfig.class);
        context.refresh();

        if (isAspectJAgentLoaded()) {
            // TODO 给自己 new的对象增加 依赖注入功能
            IndexServiceMyself self = new IndexServiceMyself();
            self.service();
        } else {
            System.err.println("@Configurable 未生效");
        }

        // TODO 非 web环境下, 希望 @PreDestroy / DisposableBean / destroy-method 生效, 需要主动注册 shutdown钩子, 如下:
        // context.registerShutdownHook();

        IndexService service = (IndexService) context.getBean("indexService");
        service.service();
        System.out.println("IndexService hashCode: " + service.hashCode());

        SetterDI setterDI = context.getBean(SetterDI.class);
        Assert.assertNotNull("setter 注入 成功", setterDI.getInnerClass());

        try {
            BeansConfig beansConfig = context.getBean(BeansConfig.class);
            fail("不扫描 `spring.DI.methodDI` 包");
        } catch (BeansException e) {
            System.out.println("Bean 扫描排除 `spring.DI.methodDI`这个包\n");
        }

        ColorEnum red = (ColorEnum) context.getBean("red");
        assertEquals("@Bean 声明的枚举对象（ColorEnum.RED）是单例的。",
                ColorEnum.RED, red);
        assertEquals("@Bean 声明的枚举对象（ColorEnum.RED）借助了 Spring的依赖注入，注入了 ApplicationContext",
                context, red.getContext());

        // 使用 map 接收相同类型的 bean
        Map<String, IndexDao> beans = context.getBeansOfType(IndexDao.class);
        System.out.println("从容器中获得 IndexDao类型的多个 bean：\n" + beans);
        System.out.println("根据别名获得 bean：" + context.getBean("indexDao1"));

        try {
            Object daoImpl2 = context.getBean("indexDaoImpl3");
            fail("容器的 qqq 环境下不存在叫 indexDaoImpl3 的 Bean，此处应该报错。。");
        } catch (BeansException e) {
            System.out.println("容器的 qqq 环境下不存在叫 indexDaoImpl3 的 Bean");
        }
    }

    public static boolean isAspectJAgentLoaded() {
        try {
            Class.forName("org.springframework.instrument.InstrumentationSavingAgent");
        } catch (ClassNotFoundException e) {
            return false;
        }
        return true;
    }

}
